package com.imooc.distributedlock;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class LockController {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 不停地请求这个接口，执行时间没有3秒的间隔
     */
    @GetMapping("lock")
    public void lock() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("解锁了！");
    }

    /**
     * 使用了redisson
     * 不停地请求这个接口，执行时间有3秒的间隔
     */
    @GetMapping("redissonLock")
    public void redissonLock() {
        RLock lock = redissonClient.getLock("lock");
        try {
            lock.lock();
            TimeUnit.SECONDS.sleep(3);
            // 这里设置30秒是为了在redis客户端可以看到设置的值，时间太短会因为过期策略自动清除
            // TimeUnit.SECONDS.sleep(30);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            log.info("解锁了！");
        }
    }

    /**
     * 使用了redisson指定时间
     * 不停地请求这个接口，接口报错
     */
    @GetMapping("redissonTimeLock")
    public void redissonTimeLock() {
        RLock lock = redissonClient.getLock("lock");
        try {
            // 超时时间太短，lock过期后执行删除操作，后面的解锁会报错
            lock.lock(5, TimeUnit.SECONDS);
            TimeUnit.SECONDS.sleep(15);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            log.info("解锁了！");
        }
    }

    /**
     * 使用了redisson的tryLock方法
     * 模拟商品抢购的场景
     */
    @GetMapping("redissonTryLock")
    public void redissonTryLock() {
        RLock lock = redissonClient.getLock("lock");
        try {
            boolean b = lock.tryLock();
            if (b) {
                // 如果拿到了锁
                log.info("开始下单...");
                // 后续耗时操作
                TimeUnit.SECONDS.sleep(3);
                lock.unlock();
                log.info("解锁了！");
            } else {
                // 没有获取到锁，再去解锁会报错，不能在finally中去解锁
                log.info("很遗憾...");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
